package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class BootStrap {

    // 定义Socket 监听端口
    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    // 初始化的一些操作
    public void start() throws Exception {

        loadConfig();

        // 定义⼀个线程池
        int corePoolSize = 10;
        int maximumPoolSize =50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("Minicat start on  ... port  " + port);

        System.out.println("================================使用线程池进行改造");
        while (true){
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, servletMap);
           // requestProcessor.start();
            threadPoolExecutor.execute(requestProcessor);
        }

    }



    private Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();


    /**
     * 加载解析web.xml，初始化Servlet
     */
    private void loadServlet(String baseUrl, String baseName){
        String webappUrl = baseUrl + "//web.xml";
        File file = new File(webappUrl);
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(file);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();

                // 根据servlet-name的值找到url-patten
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPatten = servletMapping.selectSingleNode("url-patten").getStringValue();

                // 使用包名来拼接 url
                if(baseName != null && baseName.trim().length() > 0){
                    urlPatten = "/" + baseName + urlPatten;
                }
                servletMap.put(urlPatten, (HttpServlet) Class.forName(servletClass).newInstance());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    private String appBase = "";


    /**
     * 定义loadConfig() 方法来解析加载server.xml文件
     */
    private void loadConfig() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            Element serviceElement = (Element) rootElement.selectSingleNode("//Service");
            if(serviceElement != null){
                Element connectorElement = (Element) serviceElement.selectSingleNode("Connector");
                String newPort = connectorElement.attributeValue("port") + "";
                if(newPort.trim().length() > 0){
                    this.port = Integer.parseInt(newPort);
                }
                Element engineElement = (Element) serviceElement.selectSingleNode("Engine");
                Element hostElement = (Element) engineElement.selectSingleNode("Host");
                appBase = hostElement.attributeValue("appBase") + "";

                File file = new File(appBase);
                // 遍历找出
                if(file.exists()) {
                    if(file.isDirectory()){
                        File[] files = file.listFiles();
                        if(files != null && files.length > 0){
                            for (int i=0; i<files.length; i++){
                                File project = files[i];
                                if(project.exists()) {
                                    if (project.isDirectory()) {
                                        String baseUrl = project.getAbsolutePath();
                                        String baseName = project.getName();


                                        loadServlet(baseUrl, baseName);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }




        // Minicat 的主类
        public static void main(String[] args) {
            BootStrap bootStrap = new BootStrap();
            try {
                bootStrap.start();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
}
